package org.jeecg.modules.ca.controller;

import cn.com.infosec.netsign.agent.NetSignAgent;
import cn.com.infosec.netsign.agent.NetSignResult;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.modules.base.service.BaseCommonService;
import org.jeecg.modules.ca.dto.CaDto;
import org.jeecg.modules.ca.dto.CompanyDto;
import org.jeecg.modules.ca.service.TokenService;
import org.jeecg.modules.register.entity.SubjectLegal;
import org.jeecg.modules.register.service.ISubjectLegalService;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.service.ISysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.ResourceUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.HttpRequestHandler;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;

/**
 * CA认证
 */
@Slf4j
@RestController
@RequestMapping("/api/ca")
public class CaController {

    @Resource
    private BaseCommonService baseCommonService;
    @Resource
    private TokenService tkenService;

    @Resource
    private ISysUserService sysUserService;

    @Resource
    private ISubjectLegalService subjectLegalService;

    @Resource
    private ISysUserService userService;
    @Value("${ca.filePath}")
    private String filePath;

    @ApiOperation("CA验签")
    @RequestMapping(value = "/checkSign", method = RequestMethod.GET)
    public Result<HashMap<String,Object>> checkSign(@RequestParam("signData")String signData){
        log.info(" 验签签名:  "+signData);
        try {
            /**1-调用CA验签**/
            NetSignAgent.initialize(filePath);
            NetSignResult checkResult = NetSignAgent.attachedVerify(signData, null, true);
            //返回值为1 代表验证通过
            log.info(" 验签结果:  "+checkResult.getResult());
            HashMap<String,Object> map = new HashMap<>();
            map.put("checkResult", checkResult.getResult());
            if (checkResult.getResult() != 1){
                return Result.error("验签失败"+checkResult.getResult());
            }
            return Result.ok(map);
        } catch (Exception e) {
            log.info(" 验签异常:  "+e.getMessage());
            e.printStackTrace();
        }
        return Result.error("验签失败");
    }

    @ApiOperation("CA绑定")
    @PostMapping(value = "/caBind")
    public Result<HashMap<String,Object>> caBind(@Validated @RequestBody CaDto caDto, HttpServletRequest request){
        log.info("CA绑定 验签签名:  " + caDto.getSignData() + "硬件序列号：" + caDto.getSerialNumber());
        try {
            /**1-调用CA验签**/
            NetSignAgent.initialize(filePath);
            NetSignResult checkResult = NetSignAgent.attachedVerify(caDto.getSignData(), null, true);
            //返回值为1 代表验证通过
            log.info(" 验签结果:  "+checkResult.getResult());
            HashMap<String,Object> map = new HashMap<>();
            map.put("checkResult", checkResult.getResult());
            if (checkResult.getResult() != 1){
                return Result.error("验签失败"+checkResult.getResult());
            }
            log.info("证书信息：" + checkResult.getResult(NetSignResult.SIGN_SUBJECT));
            Object obj = checkResult.getResult(NetSignResult.SIGN_SUBJECT);
            CompanyDto company = convertCert(obj.toString());

            // 获取用户信息
            SysUser sysUser = userService.getUserByName(company.getEnterpriseCode());
            if (sysUser == null){
                return Result.error("用户不存在，请先注册");
            }
            // 与当前登录用户比较，必须用户名一致
            LoginUser loginUser = (LoginUser) JwtUtil.getUserInfoByToken(request);
            if(ObjectUtil.notEqual(loginUser.getUsername(),company.getEnterpriseCode())){
                return Result.error("绑定失败，请检查CA锁与当前用户是否一致");
            }

            //修改供应商主体CA信息
            LambdaQueryWrapper<SubjectLegal> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(SubjectLegal::getLegalCode, company.getEnterpriseCode());
            SubjectLegal subjectLegal = subjectLegalService.getOne(queryWrapper) ;
            if(null != subjectLegal){
                subjectLegal.setIsCa(1);
                subjectLegal.setCasCode(caDto.getSerialNumber());
                subjectLegal.setLegalCode(company.getEnterpriseCode());
                subjectLegalService.updateCasInfo(subjectLegal);
                //有供应商的数据 设置注册完成
                sysUser.setIsRegister(2);
            }


            // 上述校验完成，设置CA已绑定
            sysUser.setIsCa(1);
            sysUser.setCasCode(caDto.getSerialNumber());
            userService.updateById(sysUser);

            return Result.ok(map);
        } catch (Exception e) {
            log.info(" 验签异常:  "+e.getMessage());
            e.printStackTrace();
        }
        return Result.error("验签失败");
    }

    @ApiOperation("CA登录")
    @RequestMapping(value = "/caLogin", method = RequestMethod.GET)
    public Result<HashMap<String,Object>> login(@RequestParam("signData")String signData){
        log.info(" 验签签名:  "+signData);
        try {
            /**1-调用CA验签**/
			NetSignAgent.initialize(filePath);
			NetSignResult checkResult = NetSignAgent.attachedVerify(signData, null, true);
			//返回值为1 代表验证通过
	        log.info(" 验签结果:  "+checkResult.getResult());
	        HashMap<String,Object> map = new HashMap<>();
	        map.put("checkResult", checkResult.getResult());
            if (checkResult.getResult() != 1){
                return Result.error("验签失败"+checkResult.getResult());
            }
            log.info("证书信息：" + checkResult.getResult(NetSignResult.SIGN_SUBJECT));
            Object obj = checkResult.getResult(NetSignResult.SIGN_SUBJECT);
            CompanyDto company = convertCert(obj.toString());

            /**2-登录**/
            //验签通过进行后台登录，创建用户账号信息，并返回前端token和用户信息
            //校验用户是否有效
            LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(SysUser::getUsername, company.getEnterpriseCode());
            SysUser sysUser = sysUserService.getOne(queryWrapper);
            Result result = sysUserService.checkUserIsEffective(sysUser);
            if(!result.isSuccess()) {
                return result;
            }

            //用户登录信息
            sysUserService.userInfo(sysUser, result, CommonConstant.USER_LOGIN_TYPE_CAS);
            //保存登录日志
            LoginUser loginUser = new LoginUser();
            loginUser.setUsername(company.getEnterpriseCode());
            baseCommonService.addLog("用户名: " + company.getEnterpriseCode() + ",登录成功！", CommonConstant.LOG_TYPE_1, null,loginUser);
            log.info("用户登录成功：" + company.getEnterpriseCode());
	        return result;
        } catch (Exception e) {
        	log.info(" 验签异常:  "+e.getMessage());
			e.printStackTrace();
		}
        return Result.error("验签失败");
    }

    private CompanyDto convertCert(String str) throws Exception {
        CompanyDto company = new CompanyDto();
        // str = 证书信息：NAME=91610136MA6WHXJU6L,CN=陕西建工新基建建设>有限公司,OU=市场开发部,O=陕西建工新基建建设有限公司,L=西安,ST=陕西,C=CN
        // 含Name的证书 组织机构代码取NAME  名称取CN
        if(str.contains("NAME=9")){
            for(String sp :str.split(",")){
                if (sp.startsWith("NAME=")){
                    company.setEnterpriseCode(sp.substring(5));
                } else if (sp.startsWith("CN=")) {
                    company.setEnterpriseName(sp.substring(3));
                } else if (sp.startsWith("E=")) {
                    company.setMail(sp.substring(2));
                } else if (sp.startsWith("L=")) {
                    company.setRegisteredArea(sp.substring(2));
                }
            }
            if(isChineseStart(company.getEnterpriseName())){
                return company;
            }else{
                throw new Exception("证书信息错误："+str);
            }
        }

        //否则另一种证书如下：
        //str=证书信息：C=CN,ST=河南省,L=开封市,O=兰考县公共资源交易中心,OU=郑州众诚建设咨询有限公司,E=309221850@qq.com,CN=91410105721844166Q,TelephoneNumber=0371-55075235
        for(String sp :str.split(",")){
            if (sp.startsWith("OU=")){
                company.setEnterpriseName(sp.substring(3));
            } else if (sp.startsWith("CN=")) {
                company.setEnterpriseCode(sp.substring(3));
            } else if (sp.startsWith("E=")) {
                company.setMail(sp.substring(2));
            } else if (sp.startsWith("L=")) {
                company.setRegisteredArea(sp.substring(2));
            }
        }
        return company;
    }

    /**
     * 判断是否中文开头
     * @param str
     * @return
     */
    public static boolean isChineseStart(String str) {
        if (str == null || str.isEmpty()) {
            return false;
        }
        char firstChar = str.charAt(0);
        return firstChar >= '\u4E00' && firstChar <= '\u9FA5';
    }

    public static void main(String[] args) {

        String signData = "MIIETQYKKoEcz1UGAQQCAqCCBD0wggQ5AgEBMQ4wDAYIKoEcz1UBgxEFADAYBgoqgRzPVQYBBAIBoAoECHRlc3RkYXRhoIIDAjCCAv4wggKioAMCAQICBAINShwwDAYIKoEcz1UBg3UFADCBijELMAkGA1UEBhMCQ04xDjAMBgNVBAgMBUhlTmFuMRIwEAYDVQQHDAlaaGVuZ1pob3UxNzA1BgNVBAoMLkhlTmFuIFByb3ZpbmNlIEluZm9ybWF0aW9uIERldmVsb3BtZW50IENvLiBMdGQxDzANBgNVBAsMBkhOWEFDQTENMAsGA1UEAwwEWEFDQTAeFw0yMjA1MjAwODU3MzJaFw0yMzA1MjAwODU3MzJaMIHIMQswCQYDVQQGEwJDTjESMBAGA1UECAwJ5rKz5Y2X55yBMRIwEAYDVQQHDAnpg5Hlt57luIIxKjAoBgNVBAoMIeays+WNl+ecgeWFrOWFsei1hOa6kOS6pOaYk+S4reW/gzEnMCUGA1UECwwe5rKz5Y2X6Lev5Y+L5bu65p2Q5pyJ6ZmQ5YWs5Y+4MR8wHQYJKoZIhvcNAQkBFhA0NjI5MTI1NzFAcXEuY29tMRswGQYDVQQDDBI5MTQxMDE4Mk1BNDRZQ1A2NFQwWTATBgcqhkjOPQIBBggqgRzPVQGCLQNCAATSRrlovmWoz75S63fVrHDpEQl90vFL+k/ZDgwsoo92JPfJX4CuLKEBYNYVktdi7BGGIBVeQtK+pyTJVLh80egFo4GzMIGwMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAfBgNVHSMEGDAWgBRs8004Sr8JshO2b6a8S1ySOIFaWzA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmhueGFjYS5jb20vY3JsL3hhY2Ffc20yLmNybDALBgNVHQ8EBAMCBsAwHQYDVR0OBBYEFB129NXAVFciOvmq7rPqodVG9Rq1MAkGA1UdEwQCMAAwDAYIKoEcz1UBg3UFAANIADBFAiBDzNuqPoeSI/elC+CkoWv+T+WBHW9QUrwP7ct53AqOmgIhAI/FNjK6nB/QozaYenWJdMsunlGmQfJ8UcBhSBMYcQ7CMYIBAjCB/wIBATCBkzCBijELMAkGA1UEBhMCQ04xDjAMBgNVBAgMBUhlTmFuMRIwEAYDVQQHDAlaaGVuZ1pob3UxNzA1BgNVBAoMLkhlTmFuIFByb3ZpbmNlIEluZm9ybWF0aW9uIERldmVsb3BtZW50IENvLiBMdGQxDzANBgNVBAsMBkhOWEFDQTENMAsGA1UEAwwEWEFDQQIEAg1KHDAMBggqgRzPVQGDEQUAMA0GCSqBHM9VAYItAQUABEcwRQIgZiZW+qndoAGGcFYo9i2Bl7sJ6FRDX6CIQLVGGReKGx8CIQDEAG+TBvj//YouZS6kohhjTv81XG/dM6XjCmO7NrRMJQ==";
        try {
        	String path = ResourceUtils.getURL("classpath:netsignagent.properties").getPath();
            
            NetSignAgent.initialize(path);
            NetSignResult result = NetSignAgent.attachedVerify(signData, null, true);
            //返回值为1 代表验证通过
            System.out.println(result.getResult());
            //获取原文
            System.out.println(new String((byte[])result.getResult(NetSignResult.PLAIN_TEXT)));
            //获取签名证书主题
            System.out.println(result.getResult(NetSignResult.SIGN_SUBJECT));
            System.out.println(result.getResult("2222222"));
            System.out.println(result.getResult(NetSignResult.DIGEST_ALG));
            System.out.println(result.getResult(NetSignResult.ENC_END_TIME));
            System.out.println(result.getResult(NetSignResult.ENC_SER_NUMBER));
            System.out.println(result.getResult(NetSignResult.RESULT_NUMBER));
            System.out.println(result.getResult(NetSignResult.SIGN_CERT));
            System.out.println(result.getResult(NetSignResult.SIGN_SER_NUMBER));
            


        } catch (Exception e) {
            e.printStackTrace();
        }


    }
}
